# 26. 抽象,接口类、多态、鸭子类型、封装
# 抽象类跟接口类
抽象类跟接口类在python中是同一种意思,但是在别的语言中就不是,比如java,在java中这二个类完全就是二个意思
抽象类跟接口类的定义:强制制定一个规范,凡是继承指定的类中必须要有指定的方法,如果没有,那么在实例化对象的时候会报错
有点抽象,但都可以用实验来验证思路
# 模拟支付 - 不使用抽象跟接口类
在不使用抽象类跟接口类的情况下,制定支付代码规范
class pay:
def pay(self):
self.pay()
class Alipay(pay):
def __init__(self,income):
self.income = income
def pay(self):
print("用户使用支付宝支付了%s元" %self.income)
class wxpay(pay):
def __init__(self,income):
self.income = income
def wxpay(self):
print("用户使用微信支付了%s元" %self.income)
wx1 = wxpay(100)
al1 = Alipay(10000)
pay.pay(al1)
pay.pay(wx1)
以上代码,如果不使用抽象类跟接口类,那有别人接手这个项目代码,如果他不清楚制定好的规范,那么这就会让微信 支付出现错误,因为在支付调用类中,指定的调用类中方法名是pay名,但是微信支付类的方法名不是按指定的方法 名,所以整个微信支付会报错
# 模拟支付 - 使用抽象跟接口类
使用抽象类跟接口类,强制定制规范,如果不按规范,就会报错
抽象类跟接口类使用需要导入一个模块
from abc import ABCMeta,abstractmethod
模拟项目需要的功能
metaclass=ABCMeta ##一个类,要让制定规范的父类继承,这样这个类才是抽象类
@abstractmethod ##强制,放在要强制让子类都必须要用的方法前面,如果子类没有这方法,实例化的时候会报错
报错
from abc import ABCMeta,abstractmethod
class pay(metaclass=ABCMeta):
@abstractmethod
def pay(self):
self.pay()
class Alipay(pay):
def __init__(self,income):
self.income = income
def pay(self):
print("用户使用支付宝支付了%s元" %self.income)
class wxpay(pay):
def __init__(self,income):
self.income = income
def wxpay(self):
print("用户使用微信支付了%s元" %self.income)
wx1 = wxpay(100)
al1 = Alipay(10000)
执行结果:
TypeError: Can't instantiate abstract class wxpay with abstract methods pay
为什么会这样,因为强制要求,只要把pay类作为父类的子类们,都必须要有pay方法,在wxpay类中没有,所以报错
正常
from abc import ABCMeta,abstractmethod
class pay(metaclass=ABCMeta):
@abstractmethod
def pay(self):
self.pay()
class Alipay(pay):
def __init__(self,income):
self.income = income
def pay(self):
print("用户使用支付宝支付了%s元" %self.income)
class wxpay(pay):
def __init__(self, income):
self.income = income
def pay(self):
print("用户使用微信支付了%s元" %self.income)
wx1 = wxpay(100)
al1 = Alipay(10000)
以上代码就是按制定好的规范来写的代码,所以不会报错
# 多态 - Python处处都是多态
python面向对象的三大特性之一
在python中无多态,因为python处处都是多态
也是因为python是一门弱类型语言
可能在别的语言中,比如java,java是一门强类型的语言,无论是赋值变量还是实例化传递参时,都是需要先声明这值是什么类型的数据,才能传递
在python中,不管是什么类型的数据,只要能传递,就能传入函数,封装到对象
# 鸭子类型 - 数据整洁概念
鸭子类型:看着像鸭子,这就是鸭子
鸭子就是让多个函数或类中的方法用处一致时,给那些方法起的名字统一
class Str:
def index(self):
pass
class List:
def index(self):
pass
class Tuple:
def index(self):
pass
以上,为什么字符串、列表、无级、都有index方法,因为他们的用处一样,这种类型也被称为鸭子类型
# 封装
封装分为二类:公有封装跟私有封装
公有封装:就是平时实例化对象,给对象空间封装一些属性,也就是公有封装
私有封装:就是私有制
目前主要是说私有封装,公有封装基本都会了
# 私有封装
私有封闭分为:私有静态字段(变量)、私有方法(函数)、私有对象属性
class A:
name = "这是一个普通的静态字段"
__name = "这是一个私有的静态字段"
def __init__(self,name,age):
self.name = name ##这是一个普通的对象属性
self.__age = age ##这是一个私有的对象属性
def cat(self):
print("这是一个普通的方法")
def __cat(self):
print("这是一个私有的方法")
# 私有静态字段 (变量)
class A:
__name = "私有"
print(__name)
def so(self):
print(self.__name)
a1 = A()
a1.so()
print(A.__name)
print(a1.__name)
# 猜这一共能出来几个"私有"
# 我说能出来二个,不信可以自己试试
# 总结
- 实例化一下对象不能访问私有字段
- 在外部使用类名也不能访问私有字段
- 就是说在外部无论使用什么方法都不能访问私有字段,有一个方法除外,下面会说
- 私有字段只能在内部使用
# 私有方法 (函数)
class a:
def __init__(self):
pass
def so(self):
self.__so()
def __so(self):
print("这是一个私有的方法")
class b(a):
def __init__(self):
self.__so()
a1 = a()
a1.so()
a.__so()
a1.__so()
b1 = b()
# 总结
- 在类的外部不能访问私有方法
- 在类的子类也不能访问私有方法
- 在类的内部可以访问私有方法
# 私有对象属性
class a:
def __init__(self):
self.__name = "这是一个私有对象"
def wo(self):
print(self.__name)
class b(a):
def __init__(self):
print(self.__name)
a1 = a()
a1.wo()
print(a1.__name)
print(a.__init__().__name)
b1 = b()
# 总结
- 在类的外部不能访问私有对象
- 在类的子类也不能访问私有对象
- 在类的内部可以访问私有对象
# 可以使用特殊手段访问私有
可以使用比较特殊的手段来访问私有封装,但是这禁止在工作项目中使用,了解就可
为什么会成为私有,无论是字段、方法、对象,python都是默认在名称前面添加了"_类名"
class A:
name = "这是一个普通的静态字段"
__name = "这是一个私有的静态字段"
def __init__(self,name,age):
self.name = name ##这是一个普通的对象属性
self.__age = age ##这是一个私有的对象属性
def cat(self):
print("这是一个普通的方法")
def __cat(self):
print("这是一个私有的方法")
print(A._A__name)
a1 = A("江凡",22)
print(a1._A__age)
A._A__cat(1)
a1._A__cat()